package com.sikulifang.bank.simulation.service.bank;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Entity;
import cn.hutool.db.Page;
import cn.hutool.db.PageResult;
import cn.hutool.db.sql.SqlBuilder;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.sikulifang.bank.simulation.constant.CodeConstants;
import com.sikulifang.bank.simulation.dto.ReceiptDTO;
import com.sikulifang.bank.simulation.dto.TransferPaymentDTO;
import com.sikulifang.bank.simulation.dto.icbc.DetailDTO;
import com.sikulifang.bank.simulation.dto.icbc.ErrorDTO;
import com.sikulifang.bank.simulation.dto.icbc.ErrorDTO.ResponseBizContentDTO;
import com.sikulifang.bank.simulation.enums.BankEnum;
import com.sikulifang.bank.simulation.util.PdfUtil;
import com.sikulifang.bank.simulation.util.R;
import com.sikulifang.frequency.core.InterfaceTypeEnum;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import static com.sikulifang.bank.simulation.constant.IcbcConstants.LDOWNEBILL;
import static com.sikulifang.bank.simulation.constant.IcbcConstants.PAYENT;
import static com.sikulifang.bank.simulation.constant.IcbcConstants.PAYPER;
import static com.sikulifang.bank.simulation.constant.IcbcConstants.QACCBAL;
import static com.sikulifang.bank.simulation.constant.IcbcConstants.QHISD;
import static com.sikulifang.bank.simulation.constant.IcbcConstants.QPAYENT;
import static com.sikulifang.bank.simulation.constant.IcbcConstants.QPAYPER;

/**
 * ClassName ICBCBankMessage
 * Description 工行
 *
 * @author Yat
 * Date 2023年6月12日, 0012 14:53
 * version 1.0
 */
@Slf4j
@Service
public class ICBCBankMessage extends AbstractBankMessage {

    @Override
    public String getActionName(String message) {
        JSONObject jsonObject = JSONUtil.parseObj(message);
        // 获取接口名称
        return jsonObject.getStr("trans_code");
    }

    @Override
    protected String getType(String actionName) {

        return switch (actionName) {
            case QACCBAL, QHISD, QPAYENT, QPAYPER, LDOWNEBILL -> InterfaceTypeEnum.query.getValue();
            case PAYENT, PAYPER -> InterfaceTypeEnum.trade.getValue();
            default -> null;
        };
    }

    @Override
    public String inlet(String message) {

        JSONObject jsonObject = JSONUtil.parseObj(message);
        // 获取接口名称
        String action = jsonObject.getStr("trans_code");

        return switch (action) {
            case QACCBAL -> queryBalance(jsonObject);
            case QHISD -> queryDetail(jsonObject);
            case PAYENT, PAYPER -> pay(jsonObject);
            case QPAYENT -> queryPayResult(jsonObject, Boolean.TRUE);
            case QPAYPER -> queryPayResult(jsonObject, Boolean.FALSE);
            case LDOWNEBILL -> receipt(jsonObject);
            default -> error("未知的接口：" + action);
        };
    }

    @SneakyThrows
    private String receipt(JSONObject jsonObject) {

        //  流水号
        String serialNo = jsonObject.getStr("ebill_serial_no");

        String sql = "select * from " + detailService.getTableName() + " where serial_no = " + serialNo + " limit 1";

        Entity entity = db.queryOne(sql);

        if (null == entity) {
            return error("系统内部错误");
        }
        Dict content = new Dict();

        String flag = entity.getStr("flag");

        String accountNo = entity.getStr("account_no");
        String accountName = entity.getStr("account_name");
        String bankName = entity.getStr("bank_name");

        String oppAccountNo = entity.getStr("opp_account_no");
        String oppAccountName = entity.getStr("opp_account_name");
        String oppBankName = entity.getStr("opp_bank_name");

        if (StrUtil.equals("D", flag)) {

            content.set("pay_account", accountNo);
            content.set("pay_acct_name", accountName);
            content.set("pay_bank_name", bankName);

            content.set("rec_account", oppAccountNo);
            content.set("rec_acct_name", oppAccountName);
            content.set("rec_bank_name", oppBankName);
        } else {

            content.set("pay_account", oppAccountNo);
            content.set("pay_acct_name", oppAccountName);
            content.set("pay_bank_name", oppBankName);

            content.set("rec_account", accountNo);
            content.set("rec_acct_name", accountName);
            content.set("rec_bank_name", bankName);
        }

        BigDecimal money = entity.getBigDecimal("money");

        content.set("return_code", 0);
        content.set("return_msg", "");
        content.set("msg_id", "1541059787043");
        content.set("trans_date", entity.getStr("tran_date"));
        content.set("ebill_serial_no", serialNo);
        content.set("pay_amt", money);
        content.set("capitalization_amt", PdfUtil.convertToAmount(money));
        content.set("use_cn", entity.getStr("use_cn"));
        content.set("post_script", entity.getStr("post_script"));
        content.set("summary", entity.getStr("summary"));
        content.set("tran_serial_no", serialNo);
        content.set("time_stamp", "");
        content.set("chan_serial_no", "");
        content.set("voucher_code", "");
        content.set("ebill_key", "");
        content.set("curr_type", "001");
        content.set("bus_type", "");
        content.set("remark", "");
        content.set("trans_net_code", "");
        content.set("trans_tellno", "");
        content.set("rep_reserved1", "");
        content.set("rep_reserved2", "");
        content.set("cus_info", "");
        content.set("acct_seq_name", "");
        content.set("prod_type", "0");
        content.set("bank_serial_no", "");
        content.set("refund_msg", "");
        content.set("agent_acct_name", "");
        content.set("agent_acct_no", "");
        content.set("ref", "");
        content.set("oref", "");
        content.set("czzhcardno", "");

        Dict dict = new Dict();
        dict.set("sign", "m4Ch3f43O8h7eW4hyQo94Mk0L");
        dict.set("response_biz_content", content);

        return JSONUtil.toJsonStr(dict);
    }

    @Override
    public R<Dict> dowReceipt(List<ReceiptDTO> receiptList) {
        return null;
    }

    @SneakyThrows
    private String queryPayResult(JSONObject jsonObject, boolean isPay) {
        String batchSerialNo = jsonObject.getStr("qry_serial_no");
        if (StrUtil.isBlank(batchSerialNo)) {
            if (isPay) {
                batchSerialNo = jsonObject.getStr("qryf_seqno");
            } else {
                batchSerialNo = jsonObject.getStr("qry_f_seq_no");
            }
        }
        if (StrUtil.isBlank(batchSerialNo)) {
            return error("流水号不能为空");
        }

        Entity find = Entity.create(detailService.getTableName()).set("batch_serial_no", batchSerialNo);

        List<Entity> list = db.find(find);

        if (list.isEmpty()) {
            return error("流水号错误，查询失败");
        }

        ArrayList<Dict> arrayList = new ArrayList<>();
        String id = IdUtil.getSnowflakeNextIdStr();
        for (Entity entity : list) {
            Dict dict;
            if (isPay) {
                dict = getQueryPay(id, entity);
            } else {
                dict = getQueryPayroll(id, entity);
            }

            Integer status = entity.getInt("status");
            if (status == 1) {
                status = 7;
            } else if (status == 2) {
                status = 6;
            }

            dict.set("result", Convert.toStr(status));

            arrayList.add(dict);

        }

        Dict content = new Dict();
        content.set("return_code", 0);
        content.set("return_msg", "");
        content.set("msg_id", "1541059787043");
        content.set("qryf_seqno", jsonObject.getStr("qryf_seqno"));
        content.set("qry_serial_no", jsonObject.getStr("qry_serial_no"));
        content.set("zip_flag", "0");
        content.set("zip", "");
        content.set("onl_bat_f", "");
        content.set("settle_mode", "0");
        content.set("package_name", "");
        content.set("rd", arrayList);

        Dict dict = new Dict();
        dict.set("response_biz_content", content);
        dict.set("sign", "m4Ch3f43O8h7eW4hyQo94Mk0L");

        return JSONUtil.toJsonStr(dict);

    }

    private Dict getQueryPay(String id, Entity entity) {
        Dict dict = new Dict();
        dict.set("uni_busi_id", id);
        dict.set("i_seqno", entity.getStr("serial_no"));
        dict.set("qryi_seqno", entity.getStr("serial_no"));
        dict.set("qry_order_no", entity.getStr("batch_serial_no"));
        dict.set("pay_type", "0");
        dict.set("pay_acc_no", entity.getStr("account_no"));
        dict.set("pay_acc_name_cn", entity.getStr("account_name"));
        dict.set("rec_acc_no", entity.getStr("opp_account_no"));
        dict.set("rec_acc_name_cn", entity.getStr("opp_account_name"));
        dict.set("sys_io_flg", "1");
        dict.set("is_same_city", "2");
        dict.set("rec_icbc_code", "200");
        dict.set("rec_city_name", "北京");
        dict.set("rec_bank_no", entity.getStr("opp_bank_no"));
        dict.set("rec_bank_name", entity.getStr("opp_bank_name"));
        dict.set("curr_type", "001");
        dict.set("pay_amt", entity.getBigDecimal("money"));
        dict.set("use_code", "");
        dict.set("use_cn", entity.getStr("use_cn"));
        dict.set("en_summary", "");
        dict.set("post_script", entity.getStr("post_script"));
        dict.set("summary", entity.getStr("summary"));
        dict.set("ref", "11");
        dict.set("oref", "");
        dict.set("erp_sqn", "");
        dict.set("bus_code", "");
        dict.set("erp_check_no", "");
        dict.set("crvouh_type", "");
        dict.set("crvouh_name", "");
        dict.set("crvouh_no", "");
        dict.set("bank_type", "");

        return dict;
    }

    private Dict getQueryPayroll(String id, Entity entity) {
        Dict dict = new Dict();
        dict.set("uni_busi_id", id);
        dict.set("i_seqno", entity.getStr("serial_no"));
        dict.set("qryi_seqno", entity.getStr("serial_no"));
        dict.set("qry_order_no", entity.getStr("batch_serial_no"));
        dict.set("payer_account", entity.getStr("account_no"));
        dict.set("payer_cnname", entity.getStr("account_name"));
        dict.set("payee_account", entity.getStr("opp_account_no"));
        dict.set("payee_cnname", entity.getStr("opp_account_name"));
        dict.set("io_flag", "1");
        dict.set("payee_bank_no", entity.getStr("opp_bank_no"));
        dict.set("payee_bank_name", entity.getStr("opp_bank_name"));
        dict.set("currency", "001");
        dict.set("pay_amt", entity.getBigDecimal("money"));
        dict.set("use_cn", entity.getStr("use_cn"));
        dict.set("postscript", entity.getStr("post_script"));
        dict.set("summary", entity.getStr("summary"));
        dict.set("ref_no", "11");
        return dict;
    }


    private String pay(JSONObject jsonObject) {
        List<TransferPaymentDTO> array = new ArrayList<>();
        JSONArray jsonArray = jsonObject.getJSONArray("rd");

        for (Object obj : jsonArray) {
            if (obj instanceof JSONObject object) {

                String payFlg = "2".equals(object.getStr("io_flag")) ? "1" : object.getStr("pay_type");

                TransferPaymentDTO payment = new TransferPaymentDTO();
                payment.setSerialNo(object.getStr("i_seq_no"));
                payment.setBatchSerialNo(jsonObject.getStr("f_seq_no"));
                payment.setPayFlg(payFlg);

                payment.setPayAccountNo(object.getStr("payer_account"));
                payment.setRecAccountNo(object.getStr("payee_account"));
                payment.setRecAccountName(object.getStr("payee_cnname"));
                payment.setRecOpenBankCode(object.getStr("payee_bank_no"));
                payment.setRecOpenBankName(object.getStr("payee_bank_name"));
                payment.setMoney(object.getBigDecimal("amount"));
                payment.setPostScript(object.getStr("postscript"));
                payment.setSummary(object.getStr("summary"));
                payment.setUseCn(object.getStr("purpose"));
                payment.setBankCode(bankCode());

                array.add(payment);
            }
        }

        R<Dict> dictR = tradingEntrance(array);
        String xml = """
                {
                    sign : "m4Ch3f43O8h7eW4hyQo94Mk0L",
                    response_biz_content : {
                        return_code : 0,
                        return_msg : "%s",
                        msg_id : "1541059787043",
                        serial_no : "%s",
                        result : "%s"
                    }
                }
                """;
        if (dictR.getCode() == CodeConstants.SUCCESS) {
            return String.format(xml, "", jsonObject.getStr("f_seq_no"), 7);
        } else {
            return String.format(xml, dictR.getMsg(), jsonObject.getStr("f_seq_no"), 6);
        }
    }

    @SneakyThrows
    private String queryDetail(JSONObject jsonObject) {

        int pageSize = 50;

        // 账户
        String account = jsonObject.getStr("account_no");
        // 最小金额
        BigDecimal lowAmount = jsonObject.getBigDecimal("min_amount");
        // 最大金额
        BigDecimal upAmount = jsonObject.getBigDecimal("max_amount");
        // 起始日期
        String startDate = jsonObject.getStr("begin_date");
        // 终止日期
        String endDate = jsonObject.getStr("end_date");
        // 借贷标志：0、借贷都查询； 1、借；2、贷（非综合 帐 户）
        String drcrf = jsonObject.getStr("drcrf");
        // 查询下页标识
        int next_tag = jsonObject.getInt("next_tag", 1);


        SqlBuilder builder = getSqlBuilder(account, lowAmount, upAmount, startDate, endDate);

        if (StrUtil.equals("1", drcrf)) {
            builder.append("and flag= 'D' ");
        } else if (StrUtil.equals("2", drcrf)) {
            builder.append("and flag = 'C' ");
        }
        Page requestPage = getRequestPage(next_tag, pageSize);

        PageResult<Entity> page = page(builder.build(), requestPage, Entity.class, builder.getParamValueArray());

        long count = page.getTotal();


        if (count == 0) {
            log.error("--------查询结果为空------");
            return error("查询结果为空");
        }

        List<DetailDTO.ResponseBizContentDTO.RdDTO> rdList = new ArrayList<>();
        for (Dict dict : page) {
            DetailDTO.ResponseBizContentDTO.RdDTO rdDTO = new DetailDTO.ResponseBizContentDTO.RdDTO();
            rdDTO.setDrcrf(dict.getStr("flag").equals("D") ? "1" : "2");
            rdDTO.setDebit_amount(dict.getBigDecimal("money"));
            rdDTO.setCredit_amount(dict.getBigDecimal("money"));
            rdDTO.setBalance(dict.getBigDecimal("balance"));
            rdDTO.setRecip_bk_no(dict.getStr("opp_bank_no"));
            rdDTO.setRecip_bk_name(dict.getStr("opp_bank_name"));
            rdDTO.setRecip_account_no(dict.getStr("opp_account_no"));
            rdDTO.setRecip_name(dict.getStr("opp_account_name"));
            rdDTO.setSummary(dict.getStr("summary"));
            rdDTO.setUse_cn(dict.getStr("use_cn"));
            rdDTO.setPost_script(dict.getStr("post_script"));
            rdDTO.setDate(dict.getStr("tran_date"));
            rdDTO.setTime(dict.getStr("tran_time"));
            rdDTO.setTh_currency("CNY");
            // 电子回单流水号
            rdDTO.setTran_serial_no(dict.getStr("serial_no"));

            rdList.add(rdDTO);
        }


        String nextTag = "";
        // 是否为最后一页
        if (count - next_tag > 1) {
            nextTag = Convert.toStr(next_tag + 1);
        }

        DetailDTO.ResponseBizContentDTO responseBizContentDTO = new DetailDTO.ResponseBizContentDTO();
        responseBizContentDTO.setReturn_code(0);
        responseBizContentDTO.setMsg_id("1541059787043");
        responseBizContentDTO.setTrans_code(jsonObject.getStr("trans_code"));
        responseBizContentDTO.setBank_code("102");
        responseBizContentDTO.setLogin_id("htt000.y.0300");
        responseBizContentDTO.setTran_date(20170426);
        responseBizContentDTO.setTran_time(105900000);
        responseBizContentDTO.setF_seq_no(jsonObject.getStr("f_seq_no"));
        responseBizContentDTO.setAccount_no(account);
        responseBizContentDTO.setAccount_name(page.get(0).getStr("account_name"));
        responseBizContentDTO.setBegin_date(startDate);
        responseBizContentDTO.setEnd_date(endDate);
        responseBizContentDTO.setMin_amount(lowAmount);
        responseBizContentDTO.setMax_amount(upAmount);
        responseBizContentDTO.setNext_tag(nextTag);
        responseBizContentDTO.setTotal_num(page.size());
        responseBizContentDTO.setRd(rdList);

        DetailDTO detailDTO = new DetailDTO();
        detailDTO.setResponse_biz_content(responseBizContentDTO);

        return JSONUtil.toJsonStr(detailDTO);
    }

    private String queryBalance(JSONObject jsonObject) {

        JSONArray rd = jsonObject.getJSONArray("rd");

        List<Dict> list = new ArrayList<>();

        for (Object o : rd) {
            JSONObject obj = JSONUtil.parseObj(o);
            String accountNo = obj.getStr("account_no");
            R<Dict> data = queryBalance(accountNo);
            if (data.getCode() == CodeConstants.ERROR) {
                return error(data.getMsg());
            }
            Dict dict = queryBalanceResponse(data.getData());
            list.add(dict);
        }

        Dict dict = new Dict();
        dict.set("return_code", 0);
        dict.set("return_msg", "");
        dict.set("msg_id", "urcnl24ciutr9");
        dict.set("trans_code", jsonObject.getStr("trans_code"));
        dict.set("cis", "020090283946236");
        dict.set("bank_code", "102");
        dict.set("login_id", "197396.y.2308");
        dict.set("tran_date", 20170714);
        dict.set("tran_time", 103231001);
        dict.set("f_seq_no", jsonObject.getStr("f_seq_no"));
        dict.set("rd", list);

        Dict result = new Dict();
        result.set("response_biz_content", dict);
        result.set("sign", "FTGECGYUYTGREVCIKKIU");

        return JSONUtil.toJsonStr(result);
    }

    private Dict queryBalanceResponse(Dict data) {

        Dict dict = new Dict();
        dict.set("i_seq_no", "1");
        // 账号
        dict.set("account_no", data.get("cardId"));
        dict.set("currency", "CNY");
        dict.set("cash_exf", 0);
        dict.set("account_property", 1);
        dict.set("yesterday_balance", 0);
        // 余额
        dict.set("balance", data.get("money"));
        dict.set("usable_balance", data.get("money"));
        dict.set("frozen_amt", 0);
        dict.set("query_time", "");
        dict.set("i_ret_code", 0);
        dict.set("i_ret_msg", "");
        dict.set("bank_type", "102");
        dict.set("account_name", data.get("accountName"));
        dict.set("hold_amt", "");
        dict.set("last_intr_date", "");
        dict.set("last_tran_date", "");
        dict.set("sub_no", "");

        return dict;

    }

    private String error(String message) {

        ResponseBizContentDTO responseBizContentDTO = new ResponseBizContentDTO();
        responseBizContentDTO.setReturn_msg(message);

        ErrorDTO errorDTO = new ErrorDTO();
        errorDTO.setResponse_biz_content(responseBizContentDTO);

        return JSONUtil.toJsonStr(errorDTO);
    }

    @Override
    public String bankCode() {
        return BankEnum.ICBC.name();
    }


}
